package com.bookworms.helloandengine.game;

import com.bookworms.helloandengine.game.ui.GameScreen;
import org.anddev.andengine.entity.IEntity;
import org.anddev.andengine.entity.layer.tiled.tmx.TMXLayer;
import org.anddev.andengine.entity.layer.tiled.tmx.TMXTile;
import org.anddev.andengine.entity.modifier.IEntityModifier.IEntityModifierListener;
import org.anddev.andengine.entity.modifier.PathModifier;
import org.anddev.andengine.entity.modifier.PathModifier.IPathModifierListener;
import org.anddev.andengine.entity.modifier.PathModifier.Path;
import org.anddev.andengine.entity.scene.Scene;
import org.anddev.andengine.util.modifier.IModifier;
import org.anddev.andengine.util.modifier.ease.EaseLinear;
import org.anddev.andengine.util.path.ITiledMap;
import org.anddev.andengine.util.path.astar.AStarPathFinder;

import static org.anddev.andengine.util.constants.Constants.VERTEX_INDEX_X;
import static org.anddev.andengine.util.constants.Constants.VERTEX_INDEX_Y;

public class UI extends GameScreen {

    public static final int MAX_PATH_SEARCH_DEPTH = 15;

    public static void GeneralUI() {
        // These must be defined for the findpath() method to work
        final ITiledMap<TMXLayer> mTiledMap = new ITiledMap<TMXLayer>() {
            @Override
            public int getTileColumns() {
                return mTMXTiledMap.getTileColumns();
            }

            @Override
            public int getTileRows() {
                return mTMXTiledMap.getTileRows();
            }

            @Override
            public boolean isTileBlocked(TMXLayer tileLayer, int tileColumn, int tileRow) {
                TMXTile blocked = TMXMapLayer.getTMXTile(tileColumn, tileRow);
                return mCollideTiles.contains(blocked);
            }

            @Override
            public float getStepCost(TMXLayer tileLayer, int fromTileColumn, int fromTileRow, int pToTileColumn, int pToTileRow) {
                return 0;
            }

            @Override
            public void onTileVisitedByPathFinder(int pTileColumn, int pTileRow) {
            }
        };
        finder = new AStarPathFinder<TMXLayer>(mTiledMap, MAX_PATH_SEARCH_DEPTH, false);
    }

    public static void walkToSelectedPoint(final float pX, final float pY, Scene pScene) {
        float[] destCoords = pScene.convertLocalToSceneCoordinates(pX, pY);
        TMXTile destinationTile = TMXMapLayer.getTMXTileAt(destCoords[VERTEX_INDEX_X], destCoords[VERTEX_INDEX_Y]);
        if (isWalking && walkingPath != null) walkToNextWayPoint(pX, pY, pScene);
        else if (walkingPath == null) {
            walkingPath = finder.findPath(TMXMapLayer, 20,
                    playerLocationTile.getTileColumn(), playerLocationTile.getTileRow(),
                    destinationTile.getTileColumn(), destinationTile.getTileRow());
            loadPathFound();
        }
    }

    private static void walkToNextWayPoint(final float pX, final float pY, final Scene pScene) {
        player.unregisterEntityModifier(mMoveModifier);
        // mPathTemp is another global PathModifier
        player.unregisterEntityModifier(mPathTemp);
        Path lPath = mCurrentPath.clone();
        // create a new path with length 2 from current sprite position to next
        // original path waypoint
        Path path = new Path(2);
        path.to(player.getX(), player.getY()).to(lPath.getCoordinatesX()[mWaypointIndex + 1],
                lPath.getCoordinatesY()[mWaypointIndex + 1]);
        // recalculate the speed.TILE_WIDTH is the tmx tile width, use yours
        float TileSpeed = path.getLength() * TOUCH_SPEED / (TILE_WIDTH);
        // Create the modifier of this subpath
        mPathTemp = new PathModifier(TileSpeed, path, getEntityModifyListener(), getPathModifierListener(pX, pY, pScene));
        player.registerEntityModifier(mPathTemp);
    }

    private static IPathModifierListener getPathModifierListener(final float pX, final float pY, final Scene pScene) {
        return new IPathModifierListener() {

            public void onPathWaypointStarted(final PathModifier pPathModifier, final IEntity pEntity, int pWaypointIndex) {
            }

            public void onPathWaypointFinished(PathModifier pPathModifier, IEntity pEntity, int pWaypointIndex) {
            }

            public void onPathStarted(PathModifier pPathModifier, IEntity pEntity) {
                mTouchLocked = true;
            }

            public void onPathFinished(PathModifier pPathModifier, IEntity pEntity) {
                mTouchLocked = false;
                player.stopAnimation();
                walkingPath = null;
                walkToSelectedPoint(pX, pY, pScene);
            }
        };
    }

    private static void loadPathFound() {

        if (walkingPath != null) {
            // Global var
            mCurrentPath = new Path(walkingPath.getLength());
            int tilewidth = mTMXTiledMap.getTileWidth();
            int tileheight = mTMXTiledMap.getTileHeight();
            for (int i = 0; i < walkingPath.getLength(); i++)
                mCurrentPath.to(walkingPath.getTileColumn(i) * tilewidth, walkingPath.getTileRow(i) * tileheight);
            doPath();
        }
    }

    private static void doPath() {
        mMoveModifier = new PathModifier(TOUCH_SPEED * walkingPath.getLength(), mCurrentPath, getEntityModifyListener(), new PathModifier.IPathModifierListener() {
            public void onPathWaypointStarted(final PathModifier pPathModifier, final IEntity pEntity, int pWaypointIndex) {
                switch (walkingPath.getDirectionToNextStep(pWaypointIndex)) {
                    case DOWN:
                        player.animate(ANIMATE_DURATION, 0, 2, true);
                        break;
                    case RIGHT:
                        player.animate(ANIMATE_DURATION, 6, 8, true);
                        break;
                    case UP:
                        player.animate(ANIMATE_DURATION, 9, 11, true);
                        break;
                    case LEFT:
                        player.animate(ANIMATE_DURATION, 3, 5, true);
                        break;
                    default:
                        break;
                }
                // Keep the waypointIndex in a Global Var
                mWaypointIndex = pWaypointIndex;
            }

            public void onPathWaypointFinished(PathModifier pPathModifier, IEntity pEntity, int pWaypointIndex) {
            }

            public void onPathStarted(PathModifier pPathModifier, IEntity pEntity) {
                // Set a global var
                isWalking = true;
            }

            public void onPathFinished(PathModifier pPathModifier, IEntity pEntity) {
                // Stop walking and set walkingPath to null
                isWalking = false;
                walkingPath = null;
                player.stopAnimation();
            }

        }, EaseLinear.getInstance()
        );
        player.registerEntityModifier(mMoveModifier);
    }

    private static IEntityModifierListener getEntityModifyListener() {
        return new IEntityModifierListener() {
            public void onModifierStarted(IModifier<IEntity> pModifier, IEntity pItem) {
            }
            public void onModifierFinished(IModifier<IEntity> pModifier, IEntity pItem) {
            }
        };
    }

}
